package com.duobaoyu.dby.supply.biz.strategy.message.refund;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import com.duobaoyu.dby.channel.adapter.bean.message.refund.AfterSaleStatusMessage;
import com.duobaoyu.dby.channel.adapter.enums.BizMessageTypeEnum;
import com.duobaoyu.dby.common.mybatis.util.EnumUtils;
import com.duobaoyu.dby.supply.biz.client.boundary.order.bean.bo.OrderBO;
import com.duobaoyu.dby.supply.biz.service.order.OrderService;
import com.duobaoyu.dby.supply.biz.service.refund.AfterSaleService;
import com.duobaoyu.dby.supply.biz.service.refund.AfterSaleStateMachine;
import com.duobaoyu.dby.supply.biz.strategy.AbstractChannelMessageAsyncHandler;
import com.duobaoyu.dby.supply.biz.util.DingDingExtUtils;
import com.duobaoyu.dby.supply.common.biz.bo.message.ChannelMessageBO;
import com.duobaoyu.dby.supply.common.biz.bo.refund.AfterSaleOutBO;
import com.duobaoyu.dby.supply.common.biz.bo.refund.AfterSaleStateContext;
import com.duobaoyu.dby.supply.common.biz.dto.refund.AfterSaleBatchQuery;
import com.duobaoyu.dby.supply.core.framework.util.FrameworkUtils;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import lombok.Data;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component;

import java.util.*;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.stream.Collectors;

import static com.duobaoyu.dby.channel.adapter.enums.ChannelCodeEnum.*;

/**
 * @author yw
 * @description
 * @date 2023/10/9 16:26
 */
@Component
@RequiredArgsConstructor
@Slf4j
public class AfterSaleStateChangeMessageAsyncHandler extends AbstractChannelMessageAsyncHandler {

    private final AfterSaleService afterSaleService;

    private final OrderService orderService;

    private final AfterSaleStateMachine afterSaleStateMachine;

    private final ThreadPoolExecutor supplyChainThreadPool;

    @Override
    protected Set<String> channelCodes() {
        return Sets.newHashSet(JD_VOP.getValue(), ONE_WALLET.getValue(), ZKH.getValue(), ALIBABA_DISTRIBUTION.getValue()
                , DE_LI.getValue(), LINKED_MALL.getValue(), ORIGINAL_LIFE.getValue());
    }

    @Override
    protected Set<Integer> bizMessageTypes() {
        return Sets.newHashSet(BizMessageTypeEnum.AFTER_SALE_ORDER_STATUS.getValue());
    }

    @Override
    protected Boolean executeHandler(ChannelMessageBO channelMessage, Object beforeResult) {
        List<AfterSaleStatusMessage> afterSaleStatusMessages = parseMessage(channelMessage);

        handleOneWalletAfterSaleMessage(afterSaleStatusMessages);
        ConvertResult convertResult = convertAfterSaleStateContext(channelMessage, afterSaleStatusMessages);
        if (Objects.isNull(convertResult)) {
            return true;
        }

        List<String> executionFailed = new ArrayList<>();
        convertResult.getSuccesses().forEach(context -> {
            boolean ret;
            try {
                ret = afterSaleStateMachine.exe(context);
            } catch (Exception e) {
                log.warn("afterSale status change throw exception,param={}", JSON.toJSONString(context), e);
                executionFailed.add(context.getAfterSale().getAfterSaleSn());
                return;
            }
            if (!ret) {
                executionFailed.add(context.getAfterSale().getAfterSaleSn());
            }
        });
        printFailureMsg(channelMessage, executionFailed, convertResult.getFailures());
        return true;
    }

    private ConvertResult convertAfterSaleStateContext(ChannelMessageBO channelMessage, List<AfterSaleStatusMessage> afterSaleStatusMessages) {
        afterSaleStatusMessages = afterSaleStatusMessages.stream()
                .filter(e -> !EnumUtils.eq(ONE_WALLET, e.getChannelCode()))
                .collect(Collectors.toList());

        if (CollectionUtils.isEmpty(afterSaleStatusMessages)) {
            return null;
        }

        List<AfterSaleOutBO> list = loadAfterSale(afterSaleStatusMessages);
        if (CollectionUtils.isEmpty(list)) {
            log.warn("no afterSale data exist,channelMessage={}", JSON.toJSONString(channelMessage));
            return null;
        }

        ConvertResult result = new ConvertResult();
        List<String> existChannelAfterSaleSns = list.stream()
                .map(AfterSaleOutBO::getChannelAfterSaleSn)
                .distinct().collect(Collectors.toList());

        Map<String, List<AfterSaleStatusMessage>> messageGroup = afterSaleStatusMessages.stream()
                .filter(e -> existChannelAfterSaleSns.contains(e.getChannelAfterSaleSn()))
                .collect(Collectors.groupingBy(AfterSaleStatusMessage::getChannelCode));

        messageGroup.forEach((k, v) -> {
            AbstractChannelAfterSaleStateChangeHandler handler = FrameworkUtils
                    .strategyInstance(AbstractChannelAfterSaleStateChangeHandler.class, k);
            Context context = new Context(v, list.stream()
                    .filter(e -> Objects.equals(k, e.getChannelCode()))
                    .collect(Collectors.toList()));
            handler.strategyHandler(context);
            result.getSuccesses().addAll(context.getHandleSuccessMessages());
            result.getFailures().addAll(context.getHandleFailureMessages());
        });
        return result;
    }


    private static class ConvertResult {

        private List<AfterSaleStateContext> successes;

        private List<AfterSaleStatusMessage> failures;

        public ConvertResult() {
            this.successes = new ArrayList<>();
            this.failures = new ArrayList<>();
        }

        public List<AfterSaleStateContext> getSuccesses() {
            return successes;
        }

        public List<AfterSaleStatusMessage> getFailures() {
            return failures;
        }
    }

    private void handleOneWalletAfterSaleMessage(List<AfterSaleStatusMessage> afterSaleStatusMessages) {
        List<AfterSaleStatusMessage> oneWalletAfterSaleMessages = afterSaleStatusMessages.stream()
                .filter(e -> EnumUtils.eq(ONE_WALLET, e.getChannelCode()))
                .collect(Collectors.toList());

        supplyChainThreadPool.execute(() -> {
            oneWalletAfterSaleMessages.forEach(e -> {
                try {
                    OrderBO order = orderService.getBaseInfoByOrderTradeSn(e.getOrderTradeSn());
                    if (Objects.isNull(order)) {
                        log.warn("壹钱包售后状态变更消息处理,订单数据不存在,同步渠道订单结束 {}", JSON.toJSONString(e));
                    } else {
                        orderService.syncChannelOrderInfo(order.getOrderSn());
                    }
                } catch (Exception ex) {
                    DingDingExtUtils.sendMessage("平安售后消息处理异常", oneWalletAfterSaleMessages);
                }
            });
        });
    }

    private void printFailureMsg(ChannelMessageBO channelMessage, List<String> executionFailed, List<AfterSaleStatusMessage> handleFailureMessages) {
        if (CollectionUtils.isNotEmpty(executionFailed)) {
            log.error("channelMessageId = {},update db failure,handleFailureMessages={}. afterSaleSn={}", channelMessage.getChannelMessageId(), executionFailed, JSON.toJSONString(handleFailureMessages));
        }
        if (CollectionUtils.isNotEmpty(handleFailureMessages)) {
            log.error("channelMessageId = {},handle channel message failure,handleFailureMessages={}", channelMessage.getChannelMessageId(), JSON.toJSONString(handleFailureMessages));
        }
    }

    /**
     * 获取售后数据
     *
     * @param afterSaleStatusMessages
     * @return
     */
    private List<AfterSaleOutBO> loadAfterSale(List<AfterSaleStatusMessage> afterSaleStatusMessages) {
        List<String> channelAfterSaleSns = afterSaleStatusMessages.stream()
                .map(AfterSaleStatusMessage::getChannelAfterSaleSn)
                .collect(Collectors.toList());
        List<String> channelOrderSns = afterSaleStatusMessages.stream()
                .map(AfterSaleStatusMessage::getChannelOrderSn)
                .filter(Objects::nonNull)
                .collect(Collectors.toList());

        AfterSaleBatchQuery batchQuery = new AfterSaleBatchQuery();
        batchQuery.setChannelAfterSaleSns(channelAfterSaleSns);
        batchQuery.setChannelOrderSns(channelOrderSns);
        return afterSaleService.batchQueryAfterSale(batchQuery);
    }


    /**
     * 解析消息
     *
     * @param channelMessage
     * @return
     */
    private List<AfterSaleStatusMessage> parseMessage(ChannelMessageBO channelMessage) {
        List<AfterSaleStatusMessage> afterSaleStatusMessages = Lists.newArrayList();
        if (StringUtils.isBlank(channelMessage.getMessage())) {
            return afterSaleStatusMessages;
        }
        Boolean isBatch = channelMessage.getIsBatch();
        if (isBatch) {
            List<AfterSaleStatusMessage> list = JSON.parseObject(channelMessage.getMessage(), new TypeReference<List<AfterSaleStatusMessage>>() {
            });
            afterSaleStatusMessages.addAll(list);
        } else {
            AfterSaleStatusMessage afterSaleStatusMessage = JSON.parseObject(channelMessage.getMessage(), AfterSaleStatusMessage.class);
            afterSaleStatusMessages.add(afterSaleStatusMessage);
        }
        return afterSaleStatusMessages;
    }

    @Data
    public static class Context {

        public Context(List<AfterSaleStatusMessage> originMessages, List<AfterSaleOutBO> afterSales) {
            this.originMessages = originMessages;
            this.afterSales = afterSales;
            this.handleSuccessMessages = new ArrayList<AfterSaleStateContext>();
            this.handleFailureMessages = new ArrayList<AfterSaleStatusMessage>();
        }

        // 原数据
        private List<AfterSaleStatusMessage> originMessages;

        private List<AfterSaleOutBO> afterSales;

        // 处理结果
        private List<AfterSaleStateContext> handleSuccessMessages;

        private List<AfterSaleStatusMessage> handleFailureMessages;
    }
}
